package com.md.model.html;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.md.util.CollectionUtil;
import com.md.util.ObjectUtil;
import com.md.value.html.LabelAttributeType;
import com.md.value.html.LabelStyleType;
import com.md.value.html.Unit;
import lombok.Data;

import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author 刘骄阳
 * 2024-05-16 1:32
 */
@Data
public class CustomLabel {
  /**
   * 样式
   */
  private final List<LabelStyle> styles;
  /**
   * 属性
   */
  private final List<LabelAttribute> attributes;
  /**
   * 标签
   */
  private final String label;
  /**
   * 内容
   */
  private String content;
  /**
   * 子集标签列表
   */
  private List<CustomLabel> childrenList;

  /**
   * 层级
   */
  private Integer level;

  private WeakReference<CustomLabel> parent;

  public CustomLabel(final String label) {
    this.label = label;
    styles = Lists.newArrayList();
    attributes = Lists.newArrayList();
  }


  public void setParent(final CustomLabel parent) {
    this.parent = new WeakReference<>(parent);
  }

  public List<LabelStyle> getAllStyle() {
    Map<String, LabelStyle> currentParentStyle = Maps.newHashMap();
    Optional.ofNullable(parent).map(WeakReference::get).map(CustomLabel::getAllStyle).ifPresent(parentStyle ->
      currentParentStyle.putAll(CollectionUtil.toMap(parentStyle, LabelStyle::getStyleName, Function.identity())));
    currentParentStyle.putAll(CollectionUtil.toMap(styles, LabelStyle::getStyleName, Function.identity()));
    return new ArrayList<>(currentParentStyle.values());
  }

  public String generateHTMLCode() {
    StringBuilder allContent = new StringBuilder();
    Optional.ofNullable(content).ifPresent(allContent::append);
    if (ObjectUtil.notEmpty(childrenList)) {
      allContent.append(childrenList.stream().map(CustomLabel::generateHTMLCode).collect(Collectors.joining()));
    }
    return generateHTMLCode(label, getAllStyle(), attributes, allContent.toString());
  }


  /**
   * @param label      标签
   * @param styles     标签的样式
   * @param attributes 标签的属性
   * @param content    标签的内容
   * @return html代码
   */
  public String generateHTMLCode(final String label,
                                 final List<LabelStyle> styles,
                                 final List<LabelAttribute> attributes,
                                 final String content) {
    // <%s%s styles='%s'>
    StringBuilder htmlCode = new StringBuilder();
    htmlCode.append("<").append(label).append(" ");

    if (ObjectUtil.notEmpty(attributes)) {
      //  %s=%s
      attributes.stream().filter(ObjectUtil::notEmpty).forEach(attribute ->
        htmlCode.append(attribute.getAttributeName()).append("=").append(attribute.getValue()).append(" "));
    }
    if (ObjectUtil.notEmpty(styles)) {
      htmlCode.append("style='");
      // %s:%s%s;
      styles.stream().filter(ObjectUtil::notEmpty).forEach(style ->
        htmlCode.append(style.getStyleName()).append(":").append(style.getValue())
          .append(style.getUnitValue()).append(";"));
      htmlCode.append("'");
    }
    htmlCode.append(">").append(content).append("</").append(label).append(">");
    return htmlCode.toString();
  }

  public void addAttribute(final LabelAttributeType attribute,
                           final Object value,
                           final Unit unit) {
    addAttribute(LabelAttribute.of(attribute, value, unit));
  }

  public void addAttribute(final LabelAttributeType attribute,
                           final Object value) {
    addAttribute(attribute, value, null);
  }

  public void addAttribute(final LabelAttribute attribute) {
    attributes.add(attribute);
  }

  public void addStyle(final LabelStyleType labelStyleType,
                       final Object value,
                       final Unit unit) {
    addStyle(LabelStyle.of(labelStyleType, value, unit));
  }

  public void addStyle(final LabelStyleType labelStyleType,
                       final Object value) {
    addStyle(labelStyleType, value, null);
  }

  public void addStyle(final LabelStyle style) {
    styles.add(style);
  }
}
